﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading;
using Common.Threading;

namespace Common.Linq
{
    public delegate Object Create();

    public class LinqToObjectsProvider<TElement> : IProvider<TElement>
        where TElement : class
    {
        private ReaderWriterLockSlim m_Sync = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
        private List<TElement> m_ElementList;
        private IQueryable<TElement> m_ElementQueryable;
        private Dictionary<String, Tuple<FieldInfo, Create>> m_Autogen = new Dictionary<String, Tuple<FieldInfo, Create>>();

        public LinqToObjectsProvider(List<TElement> list)
        {
            this.m_ElementList = list;
            this.m_ElementQueryable = new ThreadSafeQueryable<TElement>(list.AsQueryable(), this.m_Sync);
        }

        ~LinqToObjectsProvider()
        {
            this.Dispose(false);
        }

        public ICollection<String> AutoGeneratedFields
        {
            get { return m_Autogen.Keys; }
        }

        public IQueryable<TElement> Items
        {
            get { return this.m_ElementQueryable; }
        }

        public void Add(TElement newElement)
        {
            foreach (Tuple<FieldInfo, Create> autogen in this.m_Autogen.Values)
            {
                autogen.Item1.SetValue(newElement, autogen.Item2());
            }

            using (WriterLock wLock = new WriterLock(this.m_Sync))
            {
                this.m_ElementList.Add(newElement);
            }
        }

        public void Delete(TElement element)
        {
            using (WriterLock wLock = new WriterLock(this.m_Sync))
            {
                this.m_ElementList.Remove(element);
            }
        }

        public void Clear()
        {
            using (WriterLock wLock = new WriterLock(this.m_Sync))
            {
                this.m_ElementList.Clear();
            }
        }

        public void ApplyChanges()
        {
        }

        public void AddAutoGeneratedField(String field, Create create)
        {
            FieldInfo fieldInfo = typeof(TElement).GetField("_" + field, BindingFlags.NonPublic | BindingFlags.Instance);
            this.m_Autogen.Add(field, new Tuple<FieldInfo, Create>(fieldInfo, create));
        }

        public void RemoveAutoGeneratedField(String field)
        {
            this.m_Autogen.Remove(field);
        }

        #region IDisposable Members

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(Boolean disposing)
        {
        }

        #endregion
    }
}
